package com.unidt.www.module.bpm.service.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.unidt.www.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.unidt.www.framework.common.exception.util.ServiceExceptionUtil;
import com.unidt.www.framework.common.pojo.CommonResult;
import com.unidt.www.framework.common.pojo.PageResult;
import com.unidt.www.framework.common.util.date.DateUtils;
import com.unidt.www.framework.common.util.number.NumberUtils;
import com.unidt.www.framework.common.util.object.ConvertUtil;
import com.unidt.www.framework.common.util.object.PageUtils;
import com.unidt.www.module.bpm.api.task.dto.BpmProcessInstanceCreateEXTDTO;
import com.unidt.www.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO;
import com.unidt.www.module.bpm.controller.admin.task.vo.task.*;
import com.unidt.www.module.bpm.convert.task.BpmTaskConvert;
import com.unidt.www.module.bpm.dal.dataobject.definition.BpmFormDO;
import com.unidt.www.module.bpm.dal.dataobject.task.BpmDynamicAssignDo;
import com.unidt.www.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import com.unidt.www.module.bpm.dal.dataobject.task.BpmProcessTaskExtDO;
import com.unidt.www.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import com.unidt.www.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import com.unidt.www.module.bpm.dal.mysql.task.BpmDynamicAssignMapper;
import com.unidt.www.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import com.unidt.www.module.bpm.dal.mysql.task.BpmProcessTaskExtMapper;
import com.unidt.www.module.bpm.dal.mysql.task.BpmTaskExtMapper;
import com.unidt.www.module.bpm.dto.BpmDynamicAssignDto;
import com.unidt.www.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
import com.unidt.www.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.unidt.www.module.bpm.service.definition.BpmFormService;
import com.unidt.www.module.bpm.service.message.BpmMessageService;
import com.unidt.www.module.bpm.vo.BpmFormVo;
import com.unidt.www.module.system.api.dept.DeptApi;
import com.unidt.www.module.system.api.dept.dto.DeptRespDTO;
import com.unidt.www.module.system.api.user.AdminUserApi;
import com.unidt.www.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.unidt.www.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.unidt.www.framework.common.pojo.CommonResult.error;
import static com.unidt.www.framework.common.pojo.CommonResult.success;
import static com.unidt.www.framework.common.util.collection.CollectionUtils.convertMap;
import static com.unidt.www.framework.common.util.collection.CollectionUtils.convertSet;
import static com.unidt.www.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
import static com.unidt.www.module.bpm.enums.ErrorCodeConstants.*;

/**
 * 流程任务实例 Service 实现类
 *
 * @author 华院计算源码
 * @author jason
 */
@Slf4j
@Service
public class BpmTaskServiceImpl implements BpmTaskService {

    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    @Resource
    private BpmProcessInstanceService processInstanceService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private DeptApi deptApi;
    @Resource
    private BpmTaskExtMapper taskExtMapper;
    @Resource
    private BpmMessageService messageService;

    @Resource
    private BpmFlowElementService bpmFlowElementService;
    @Resource
    RepositoryService repositoryService;
    @Resource
    RuntimeService runtimeService;
    @Resource
    BpmFormService bpmFormService;

    @Resource
    BpmProcessDefinitionExtMapper bpmProcessDefinitionExtMapper;

    @Resource
    BpmProcessInstanceExtMapper processInstanceExtMapper;

    @Resource
    private BpmProcessTaskExtMapper processTaskExtMapper;

    @Resource
    BpmDynamicAssignMapper bpmDynamicAssignMapper;

    @Resource
    private BpmActivityService activityService;

    private static String NEXT_ASSIGNEE = "nextAssignee";


    @Override
    public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByTaskCreateTime().desc(); // 创建时间倒序
        if (StrUtil.isNotBlank(pageVO.getName())) {
            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
        }
        if (pageVO.getBeginCreateTime() != null) {
            taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
        }
        if (pageVO.getEndCreateTime() != null) {
            taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
        }
        // 执行查询
        List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
        if (CollUtil.isEmpty(tasks)) {
            return PageResult.empty(taskQuery.count());
        }

        List<String> processDefinitionIds = tasks.stream().map(e -> e.getProcessDefinitionId()).collect(Collectors.toList());
        processDefinitionIds = processDefinitionIds.stream().distinct().collect(Collectors.toList());

        List<BpmFormVo> formVos = this.bpmProcessDefinitionExtMapper.getFromByProcessDefinitionIds(processDefinitionIds);

        Map<String, BpmFormVo> formVoMap =
                formVos.stream().collect(Collectors.toMap(BpmFormVo::getProcessDefinitionId, a -> a, (k1, k2) -> k1));

        // 获得 ProcessInstance Map
        Map<String, ProcessInstance> processInstanceMap =
                processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));


        // 拼接结果
        return new PageResult<>(BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap, formVoMap),
                taskQuery.count());
    }

    @Override
    public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
        // 查询已办任务
        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
                .taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
        if (StrUtil.isNotBlank(pageVO.getName())) {
            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
        }
        if (pageVO.getBeginCreateTime() != null) {
            taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
        }
        if (pageVO.getEndCreateTime() != null) {
            taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
        }
        // 执行查询
        List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
        if (CollUtil.isEmpty(tasks)) {
            return PageResult.empty(taskQuery.count());
        }

        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs =
                taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
                processInstanceService.getHistoricProcessInstanceMap(
                        convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));

        List<String> processDefinitionIds = tasks.stream().map(e -> e.getProcessDefinitionId()).collect(Collectors.toList());
        processDefinitionIds = processDefinitionIds.stream().distinct().collect(Collectors.toList());

        List<BpmFormVo> formVos = this.bpmProcessDefinitionExtMapper.getFromByProcessDefinitionIds(processDefinitionIds);


        Map<String, BpmFormVo> formVoMap =
                formVos.stream().collect(Collectors.toMap(BpmFormVo::getProcessDefinitionId, a -> a, (k1, k2) -> k1));

        // 拼接结果
        return new PageResult<>(
                BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap, formVoMap),
                taskQuery.count());
    }


    @Override
    public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
        if (CollUtil.isEmpty(processInstanceIds)) {
            return Collections.emptyList();
        }
        return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
    }

    @Override
    public List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId) {
        // 获得任务列表
        List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
                .list();
        if (CollUtil.isEmpty(tasks)) {
            return Collections.emptyList();
        }

        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
        // 获得 User Map
        Set<Long> userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee()));
        userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
        // 获得 Dept Map
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));

        // 拼接数据
        return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {

        Task task = checkTask(userId, reqVO.getId());

        String nextAcctId = getTaskDefKey(task);

        Map<String, Object> variables = taskService.getVariables(task.getId());


        /**
         * 下一流程节点不为空
         * 下一流程节点审批人不为空
         * 动态改变流程审核人
         */

        String nextAssignee = "";
        if (variables.containsKey(NEXT_ASSIGNEE)) {

            LinkedHashMap map =(LinkedHashMap) variables.get(NEXT_ASSIGNEE);
            List list = (List)map.get("selected");
            if(!list.isEmpty()){
                nextAssignee =   list.get(0).toString();
            }

        }

        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }

        try {
            taskService.complete(task.getId(), instance.getProcessVariables());

            // 更新任务拓展表为通过
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                            .setReason(reqVO.getReason()));


            /**
             * 下个节点换人
             */

            if (StringUtils.isNotBlank(nextAcctId) && StringUtils.isNotBlank(nextAssignee)) {
                List<BpmActivityRespVO>  mList  =activityService.getActivityListByProcessInstanceId(instance.getProcessInstanceId());
                for(BpmActivityRespVO mBpmActivityRespVO:mList){
                    if(mBpmActivityRespVO.getKey().equals(nextAcctId)){
                        updateTaskAssignee(mBpmActivityRespVO.getTaskId(),Long.valueOf(nextAssignee));
                    }
                }

            }


        } catch (Exception e) {

            log.error("审批通过异常", e);
            //报错的话，就走完成委派功能。
            taskService.resolveTask(task.getId(), instance.getProcessVariables());
            // 更新任务拓展表为通过
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
                            .setReason(reqVO.getReason()));

        }






    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
        Task task = checkTask(userId, reqVO.getId());
        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }

        // 更新流程实例为不通过
        processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());

        // 更新任务拓展表为不通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
                        .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
    }

    @Override
    public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
        // 校验任务存在
        Task task = checkTask(userId, reqVO.getId());
        // 更新负责人
        updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
    }

    @Override
    public void updateTaskAssignee(String id, Long userId) {
        taskService.setAssignee(id, String.valueOf(userId));
    }

    /**
     * 校验任务是否存在， 并且是否是分配给自己的任务
     *
     * @param userId 用户 id
     * @param taskId task id
     */
    private Task checkTask(Long userId, String taskId) {
        Task task = getTask(taskId);
        if (task == null) {
            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        log.info("userId:"+userId);
        log.info("task.id:"+task.getId());
        log.info("task.getAssignee():"+task.getAssignee());
        if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
            throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
        }
        return task;
    }

    /**
     * 校验任务是否存在
     *
     * @param taskId task id
     */
    private Task checkTask(String taskId) {
        Task task = getTask(taskId);
        if (task == null) {
            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        return task;
    }

    @Override
    public void createTaskExt(Task task) {
        BpmTaskExtDO taskExtDO =
                BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        taskExtMapper.insert(taskExtDO);
    }

    @Override
    public void updateTaskExtComplete(Task task) {
        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大，因为 Complete 一般是审核通过，已经设置
                .setEndTime(LocalDateTime.now());
        taskExtMapper.updateByTaskId(taskExtDO);
    }

    @Override
    public void updateTaskExtCancel(String taskId) {
        // 需要在事务提交后，才进行查询。不然查询不到历史的原因
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

            @Override
            public void afterCommit() {
                // 可能只是活动，不是任务，所以查询不到
                HistoricTaskInstance task = getHistoricTask(taskId);
                if (task == null) {
                    return;
                }

                // 如果任务拓展表已经是完成的状态，则跳过
                BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId);
                if (taskExt == null) {
                    log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录，可能存在问题]", taskId);
                    return;
                }
                // 如果已经是最终的结果，则跳过
                if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) {
                    log.error("[updateTaskExtCancel][taskId({}) 处于结果({})，无需进行更新]", taskId, taskExt.getResult());
                    return;
                }

                // 更新任务
                taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
                        .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
            }

        });
    }

    @Override
    public void updateTaskExtAssign(Task task) {
        BpmTaskExtDO taskExtDO =
                new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId());
        taskExtMapper.updateByTaskId(taskExtDO);
        // 发送通知。在事务提交时，批量执行操作，所以直接查询会无法查询到 ProcessInstance，所以这里是通过监听事务的提交来实现。
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {

                ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());

                AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));

                messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
            }
        });
    }

    /**
     * 实现加签功能
     *
     * @param reqVO
     * @return
     */
    @Override
    public CommonResult<String> addSignTask(BpmTaskSignVO reqVO) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        //通过delegateTask实现加签
        taskService.delegateTask(reqVO.getTaskId(), reqVO.getUserId() + "");
        return success("加签成功");

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<String> fallback(BpmTaskBackVO backVO) {


        Long userId = getLoginUserId();

        String taskId = backVO.getTaskId();
        /**
         * 校验任务
         */
        Task task = checkTask(taskId);
        String processInstanceId = task.getProcessInstanceId();
        String deploymentId = processInstanceService.getProcessInstance(processInstanceId).getDeploymentId();

        String modelId = repositoryService.createModelQuery().deploymentId(deploymentId).singleResult().getId();
        /**
         * 当前节点任务人
         * 是否是登录人 是登录人则可以进行操作
         */
        String assignee = task.getAssignee();


        if (!assignee.equals(String.valueOf(userId))) {
            return CommonResult.error(GlobalErrorCodeConstants.UNKNOWN.getCode(), "回退必须由本人操作");

        }

        String tasKey = task.getTaskDefinitionKey();

        List<FlowElement> flowElementList = bpmFlowElementService.calApprovePath(processInstanceId, modelId, taskService.getVariables(task.getId()));
        flowElementList = flowElementList.stream().filter(e -> e instanceof UserTask).collect(Collectors.toList());


        if (!flowElementList.isEmpty()) {

            String lastTaskKey = "";

            for (int i = 0; i < flowElementList.size(); i++) {
                FlowElement element = flowElementList.get(i);
                String actKey = element.getId();
                if (actKey.equals(tasKey)) {
                    if (i == 0) {
                        return CommonResult.error(GlobalErrorCodeConstants.UNKNOWN.getCode(), "当前节点不能回退！");
                    }
                    lastTaskKey = flowElementList.get(i - 1).getId();

                    break;
                }
                if((i==flowElementList.size()-1)&&StringUtils.isBlank(lastTaskKey)){
                    lastTaskKey = flowElementList.get(i-1).getId();
                }
            }

            BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId);
            // 更新任务
            taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.BACK.getResult())
                    .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason("任务回退，原因:" + backVO.getReason())));

            //回退（节点跳转）
            if(StringUtils.isNotBlank(tasKey)&&StringUtils.isNotBlank(lastTaskKey)){
                runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(processInstanceId)
                        .moveActivityIdTo(tasKey, lastTaskKey)
                        .changeState();
                return success("撤回成功！请尽快完成任务。");
            }

            return success("当前调用活动！不可回退。");



        } else {
            return error(GlobalErrorCodeConstants.UNKNOWN.getCode(), "没有上一步节点 不能回退");
        }


    }

    @Override
    public CommonResult<BpmFormDO> getTaskBpmForm(String taskId) {

        Task task = checkTask(taskId);
        String processInstanceId = task.getProcessInstanceId();
        try {
            Long formKey = Long.valueOf(task.getFormKey());
            BpmFormDO mBpmFormDO = bpmFormService.getForm(formKey);
            return CommonResult.success(mBpmFormDO);
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        return CommonResult.success(null);
    }

    @Override
    /**
     * 保存流程节点表单
     * 此时将自定义表单的变量值传递过来，需加入runtime service中
     */
    public CommonResult<String> createTaskIdForFormKeyInfo(Long userId, String taskId, @Valid BpmProcessInstanceCreateEXTDTO createReqDTO) {

        Task task = checkTask(taskId);
        String processInstanceId = task.getProcessInstanceId();
        // 创建流程实例
        BpmProcessInstanceExtDO mBpmProcessInstanceExtDO = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId);

        BpmProcessTaskExtDO mBpmProcessTaskExtDO = new BpmProcessTaskExtDO();
        BeanUtils.copyProperties(mBpmProcessInstanceExtDO, mBpmProcessTaskExtDO);


        // 补全流程实例的拓展表
        mBpmProcessTaskExtDO.setId(null);
        mBpmProcessTaskExtDO.setProcessExecutionId(task.getExecutionId());//为了不重样，借用流程实例字段放执行字段。
        mBpmProcessTaskExtDO.setTaskId(taskId);
        mBpmProcessTaskExtDO.setFormVariables(createReqDTO.getVariables());
        processTaskExtMapper.insertByTaskId(mBpmProcessTaskExtDO);

        //
        // 遍历变量，添加到运行时变量中
        for (Map.Entry<String, Object> entry : createReqDTO.getVariables().entrySet()) {
            log.info("表单====key:" + entry.getKey() + "value:" + entry.getValue());
            runtimeService.setVariable(processInstanceId, entry.getKey(), entry.getValue());
        }

        return CommonResult.success("保存表单成功");
    }

    @Override
    public CommonResult<BpmProcessTaskExtDO> getByTaskIdFormInfo(Long userId, String taskId) {
        return CommonResult.success(processTaskExtMapper.selectByTaskId(new BpmProcessTaskExtDO().setTaskId(taskId)));
    }


    private Task getTask(String id) {
        return taskService.createTaskQuery().taskId(id).singleResult();
    }

    private HistoricTaskInstance getHistoricTask(String id) {
        return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
    }


    @Override
    public CommonResult<String> automationBpmbyOver(String id) {

        List<ActivityInstance> mlist = runtimeService.createActivityInstanceQuery().processInstanceId(id)
                .list().stream()
                .filter(p -> p.getEndTime() == null)
                .filter(p -> p.getActivityType().equals("userTask"))
                .collect(Collectors.toList());

        for (ActivityInstance mActivityInstance : mlist) {

            approveTask(Long.valueOf(mActivityInstance.getAssignee()),
                    new BpmTaskApproveReqVO().setId(mActivityInstance.getTaskId()).setReason("同意！")
            );

        }
        return CommonResult.success("流程自动完成");
    }

    @Override
    public List<UserTask> getNextTask(String taskId) {

        List<UserTask> taskList = new ArrayList<>();
        Task task = checkTask(taskId);
        task.getAssignee();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();

        for (SequenceFlow sequenceFlow : outFlows) {
            // 下一个审批节点
            FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
            //如果是用户任务则获取待办人或组
            if (targetFlow instanceof UserTask) {
                // 如果下个审批节点为userTask
                UserTask userTask = (UserTask) targetFlow;
                taskList.add(userTask);
            }
        }
        return taskList;
    }

    @Override
    public void claim(String taskId, String replace_assign) {
        this.taskService.claim(taskId, replace_assign);
    }

    /**
     * 功能描述: 设置下一节点审批人
     *
     * @param currentTask
     * @param nextActId
     * @param nextAssignee
     * @return java.lang.Boolean
     * @author sk
     * @date 2023/2/13
     */
    public Boolean setDynamicAssign(Task currentTask, String nextActId, String nextAssignee) {
        BpmDynamicAssignDto assignDto = new BpmDynamicAssignDto(
                currentTask.getProcessInstanceId(),
                currentTask.getProcessDefinitionId(),
                currentTask.getTaskDefinitionKey(),
                nextActId,
                nextAssignee
        );
        BpmDynamicAssignDo bpmDynamicAssignDo = this.bpmDynamicAssignMapper.getByProcessInstanceIdAndActId(assignDto.getProcInstId()
                , assignDto.getExeActId());

        if (bpmDynamicAssignDo == null) {
            bpmDynamicAssignDo = ConvertUtil.convert(assignDto, BpmDynamicAssignDo.class);
            this.bpmDynamicAssignMapper.insert(bpmDynamicAssignDo);
        } else {
            bpmDynamicAssignDo.setAssignee(assignDto.getAssignee());
            this.bpmDynamicAssignMapper.updateById(bpmDynamicAssignDo);
        }


        return true;
    }

    /**
     * 功能描述: 根据条件选择 判断下一个流程节点
     *
     * @param task
     * @return java.lang.String
     * @author sk
     * @date 2023/2/13
     */
    private String getTaskDefKey(Task task) {
        /**
         * 设置下一节点审核人
         * 判断前端传入变量
         */
        String processInstanceId = task.getProcessInstanceId();

        String deploymentId = processInstanceService.getProcessInstance(processInstanceId).getDeploymentId();
        String modelId = repositoryService.createModelQuery().deploymentId(deploymentId).singleResult().getId();

        List<FlowElement> flowElementList = bpmFlowElementService.calApprovePath(processInstanceId, modelId, taskService.getVariables(task.getId()));
        flowElementList = flowElementList.stream().filter(e -> e instanceof UserTask).collect(Collectors.toList());

        /**
         * 获取下一个节点
         */
        String currentActId = task.getTaskDefinitionKey();
        String nextTaskKey = "";
        for (int i = 0; i < flowElementList.size(); i++) {
            if (i == flowElementList.size() - 1) {
                /**
                 * 最后一个节点
                 */
                break;
            }
            FlowElement element = flowElementList.get(i);
            String actKey = element.getId();
            if (actKey.equals(currentActId)) {
                nextTaskKey = flowElementList.get(i + 1).getId();
                break;
            }
        }
        return nextTaskKey;
    }
}
